// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: jing

#pragma once

#include <algorithm>
#include <functional>
#include <map>
#include <string>
#include <vector>

#include "coin2/exchange/base/feed/processor.h"

namespace coin2::exchange::bithumb::feed_v2 {
namespace impl {

class BithumbRequestGenerator : public base::feed::RequestGenerator {
 public:
  std::vector<std::string> GenerateRequests(
      const std::vector<std::string>& channels,
      const std::vector<std::string>& symbols,
      const std::map<std::string, std::string>& channel_templates,
      const std::string& request_template) override {
    std::vector<std::string> reqs;

    std::vector<std::string> ch = channels;
    std::vector<std::string> ch_kline;
    auto iter = ch.begin();
    while (iter != ch.end()) {
      if (StringStartsWith(*iter, "kline_rest")) {
        ch_kline.push_back(*iter);
        iter = ch.erase(iter);
      } else {
        iter++;
      }
    }
    if (!ch_kline.empty()) {
      for (auto& ch_k : ch_kline) {
        for (auto& symbol : symbols) {
          std::string c = channel_templates.at(ch_k);
          boost::replace_all(c, "{}", symbol);
          std::string request = request_template;
          boost::replace_all(request, "{channel}", c);
          reqs.push_back(request);
        }
      }
    }

    std::vector<std::string> ch_book_rest;
    iter = ch.begin();
    while (iter != ch.end()) {
      if (StringStartsWith(*iter, "snapshot")) {
        ch_book_rest.push_back(*iter);
        iter = ch.erase(iter);
      } else {
        iter++;
      }
    }
    if (!ch_book_rest.empty()) {
      for (auto& ch_b : ch_book_rest) {
        for (auto& symbol : symbols) {
          std::vector<std::string> splitted = Split(symbol, "_");
          CHECK_EQ(splitted.size(), 2);
          std::string& payment_currency = splitted[1];
          std::string c = channel_templates.at(ch_b);
          boost::replace_all(c, "{}", payment_currency);
          std::string request = request_template;
          boost::replace_all(request, "{channel}", c);
          reqs.push_back(request);
        }
      }
    }

    std::vector<std::string> symbols_in_quotes;
    for (const auto& sym : symbols) {
      symbols_in_quotes.push_back("\"" + sym + "\"");
    }
    std::string symbol_list = boost::algorithm::join(symbols_in_quotes, ",");
    for (auto& channel : ch) {
      std::string c = channel_templates.at(channel);
      boost::replace_all(c, "{}", symbol_list);
      std::string request = request_template;
      boost::replace_all(request, "{channel}", c);
      reqs.push_back(request);
    }



    // For some unknown reason, when a request contains more than one symbols,
    // we are not getting any trade messages if the book request is sent before
    // the trade request.  This is just a hack to reorder the request so that
    // trade comes before book.
    std::sort(reqs.begin(), reqs.end(), std::greater<std::string>());

    return reqs;
  }
};

}  // namespace impl
using impl::BithumbRequestGenerator;
}  // namespace coin2::exchange::bithumb::feed_v2
